﻿using Library.Common.Common;
using Library.Common.Model;
using Library.Common.Network;
using Library.Common.Serialize;
using Library.Core.Application.IInfrastructure.Event;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Synthesize.Common.Application.MessageTopic;
using Synthesize.Common.Domain.Aggregation.ValueObject;
using Synthesize.Common.Domain.Event;
using Synthesize.Common.ServiceInterface.Query;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SMS.WebApi.App_Start.Filter
{
    /// <summary>
    ///接口安全特性
    /// </summary>
    public class ApiSafeFilter : ActionFilterAttribute
    {
        /// <summary>
        /// 接口请求参数
        /// </summary>
        private StringBuilder action_params = null;
        private readonly IEventBus _eventBus;
        private readonly ISafeQueryService _safeQueryService;

        /// <summary>
        /// 接口安全特性
        /// </summary>
        /// <param name="eventBus"></param>
        /// <param name="safeQueryService"></param>
        public ApiSafeFilter(IEventBus eventBus
           
            , ISafeQueryService safeQueryService
            )
        {
            _eventBus = eventBus;
            _safeQueryService = safeQueryService;
        }

        /// <summary>
        ///  验证用户信息
        /// </summary>
        /// <param name="filterContext"></param>
        /// <param name="next"></param>
        public async override Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
        {
            var requestIp = HttpHelper.GetIP(filterContext.HttpContext);

            var resultInfo = new BaseApiResult<string>();

            //判断是否在黑名单中
            var allNameListInfo = await _safeQueryService.GetMonitorLogList();
            if (allNameListInfo != null && allNameListInfo.Any())
            {
                var isBlackList = allNameListInfo.Exists(p => p.request_ip.Equals(requestIp) && p.name_type == (int)NameListTypeEnum.NoAccess);
                if (isBlackList)
                {
                    resultInfo.Code = (int)CustomError.InvalidOperation;
                    resultInfo.Data = "被禁用IP！";
                    resultInfo.Msg = "被禁用IP！";
                }
            }

            //过滤SQL注入
            var descriptor = filterContext.ActionDescriptor as ControllerActionDescriptor;
            if (resultInfo.Code == (int)CustomError.Success)
            {
                //获取接口获取到的参数
                if (descriptor.Parameters.Count > 0)
                {
                    action_params = new StringBuilder();
                    foreach (var item in descriptor.Parameters)
                    {
                        if (filterContext.ActionArguments.Count > 0)
                        {
                            action_params.Append($"{{{item.Name}:{ JsonHelper.ToJson(filterContext.ActionArguments[item.Name])}}}");
                        }
                    }
                }

                //过滤SQL注入
                if (action_params != null)
                {
                    bool safeString = StringHelper.IsSafeSqlString(action_params.ToString());
                    if (!safeString)
                    {
                        resultInfo.Code = (int)CustomError.SafetyError;
                        resultInfo.Data = "包含SQL注入相关的非法字符串！";
                        resultInfo.Msg = "包含SQL注入相关的非法字符串！";
                    }
                }
            }

            //防重放攻击
            if (resultInfo.Code == (int)CustomError.Success)
            {
                if (filterContext.HttpContext.Request.Headers.Keys.Contains("timestamp"))
                {
                    //var timestamp = filterContext.HttpContext.Request.Headers["timestamp"].ToString();
                    //var isReplayAttack = await _safeServicecs.JudgeReplayAttack(requestIp, timestamp);
                    //if (isReplayAttack)
                    //{

                    //    resultInfo.Code = (int)CustomError.SafetyError;
                    //    resultInfo.Data = "重放非法请求！";
                    //    resultInfo.Msg = "重放非法请求！";
                    //}
                }
                else
                {
                    resultInfo.Code = (int)CustomError.SafetyError;
                    resultInfo.Data = "非法请求！";
                    resultInfo.Msg = "非法请求！";
                }
            }

            //接口请求日记记录操作
            if (!string.IsNullOrEmpty(filterContext.HttpContext.Request.Path.ToString()))
            {
                //记录接口日志
                var log = new SafeApiMonitorLogEvent()
                {
                    Id = Guid.NewGuid().ToString().Replace("-", ""),
                    ServiceName = ServiceNameEnum.DevOpsService.GetDescription(),
                    ControllerName = descriptor.ControllerName,
                    ActionName = descriptor.ActionName,
                    ActionParams = descriptor.Parameters.Count > 0 ? action_params.ToString() : "",
                    RequestTime = DateTime.Now,
                    HttpHeader = JsonHelper.ToJson(filterContext.HttpContext.Request.Headers.Values),
                    RequestIp = requestIp,
                    RequestPath = filterContext.HttpContext.Request.Path.ToString(),
                    HttpMethod = filterContext.HttpContext.Request.Method,
                };
                await _eventBus.PublishAsync(TopicName.ApiLog, log);
            }


            if (resultInfo.Code != (int)CustomError.Success)
            {
                ActionException(filterContext, resultInfo);
            }

            await base.OnActionExecutionAsync(filterContext, next);
        }


        /// <summary>
        /// Action执行后发生
        /// </summary>
        /// <param name="actionExecutedContext">执行后的上下文</param>
        public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
        }

        /// <summary>
        /// 失败返回处理
        /// </summary>
        /// <param name="filterContext"></param>
        /// <param name="message">失败信息</param>
        public void ActionException(ActionExecutingContext filterContext, BaseApiResult<string> message)
        {
            filterContext.Result = new JsonResult(message);
            filterContext.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }
}
